AddCSLuaFile(	"cl_init.lua")
AddCSLuaFile(	"shared.lua")
AddCSLuaFile(	"shd_config.lua")
AddCSLuaFile(	"shd_ragspec.lua")
AddCSLuaFile(	"shd_viewpunch.lua")
AddCSLuaFile(	"cl_vgui.lua")

include(		"shared.lua")
include(		"sv_walljump.lua")
include(		"sv_svn.lua")
include(		"sv_dropweapon.lua")
include(		"shd_ragspec.lua")
include(		"shd_viewpunch.lua")

PLAYER_RELOAD_SHOTGUN = 9001
PLAYER_ROLL_LEFT = 9002
PLAYER_ROLL_RIGHT = 9003

--[[
for _,f in pairs( file.Find("../models/donatr/*") ) do
	resource.AddFile( "models/donatr/" .. f )
end

for _,f in pairs( file.Find("../materials/models/donatr/*") ) do
	resource.AddFile( "materials/models/donatr/" .. f )
end

for _,f in pairs( file.Find("../materials/models/jake1/*") ) do
	resource.AddFile( "materials/models/jake1/" .. f )
end
]]

for _,f in pairs( file.Find("../models/weapons/v_gpk*") ) do
	resource.AddFile( "models/weapons/" .. f )
end

local PlayerMeta = FindMetaTable("Player")

function GM:PlayerDeathSound()
	return true
end

function GM:ShowHelp( ply )
	umsg.Start("gpk_ShowMenu",ply)
	umsg.End()
end

function GM:PlayerInitialSpawn(ply)
	ply.Speed = 0
	ply.MinSpeed = 100
	ply.MaxSpeed = MAXSPEED
	ply.CurMaxSpeed = MAXSPEED
	ply.CrawlSpeed = 200
	ply.Acceleration = 1.5
	
	ply.WalljumpCombo = 0

	ply.WalljumpTimer = CurTime()
	ply.HealTimer = CurTime()
	
	if ply:IsAdmin() then
		ply.OverridePickup = ADMIN_WEPICKUP
	else
		ply.OverridePickup = WEPICKUP
	end
	
	ply:SetNWString( "SteamID", ply:SteamID() )
end

function GM:PlayerSpawn(ply)
	ply.Speed = 0
	
	if ply:IsSuperAdmin() then
		ply:SetTeam(1)
	elseif ply:IsAdmin() then
		ply:SetTeam(2)
	elseif ply:IsUserGroup("donator") then
		ply:SetTeam(3)
	else
		ply:SetTeam(4)
	end
	
	ply.WRunning = false
	ply.WTime = 0
	ply.Hanging = false
	ply:SetMoveType(MOVETYPE_WALK)
	ply.WRunStart = CurTime()
	ply:ViewPunchReset()
	
	if not ply:GetData() then
		ply:CreateData()
	else
		ply.Data = ply:GetData()
	end
	
	hook.Call( "PlayerLoadout", GAMEMODE, ply )
	hook.Call( "PlayerSetModel", GAMEMODE, ply )
end

function GM:PlayerLoadout( ply )
	ply.OverridePickup = true
	ply:Give("weapon_gpk_fists")
	--ply:Give("weapon_gpk_tagger")
	--ply:Give("weapon_gpk_crowbar")
	--ply:Give("weapon_gpk_pistol")
	if ply:IsAdmin() then
		ply.OverridePickup = ADMIN_WEPICKUP
	else
		ply.OverridePickup = WEPICKUP
	end
	ply:SetArmor(0)
	ply:DrawWorldModel(false)
	ply:SetJumpPower(150)
	return true
end

function GM:PlayerSetModel( ply )
	
	if not ply.Data then
		ply:CreateData()
		ply.Data = ply:GetData()
	end
	
	local model = ply.Data
	
	util.PrecacheModel( model )
	ply:SetModel( model )
	
end

function PlayerMeta:CreateData()
	file.Write( "gpk/" .. string.gsub(self:SteamID(), ":", "_") .. ".txt", "models/player/kleiner.mdl" )
end

function PlayerMeta:GetData()
	if not file.Exists( "gpk/" .. string.gsub(self:SteamID(), ":", "_") .. ".txt" ) then
		return false
	else
		return file.Read( "gpk/" .. string.gsub(self:SteamID(), ":", "_") .. ".txt" )
	end
end

function PlayerMeta:SaveData( data )
	file.Write( "gpk/" .. string.gsub(self:SteamID(), ":", "_") .. ".txt", data )
end

function GM.HealthRegen()
	for _,ply in pairs( player.GetAll() ) do
		if ply:Alive() then
			local hp = ply:Health()
			ply:SetHealth( math.Clamp( hp + REGEN, 0, 100 ) )
		end
	end
end
timer.Create( "HPRegen", REGENTIME, 0, GM.HealthRegen )

function ReduceFallDamage( ent, inflictor, attacker, amount, dmginfo )
	if (!ent:IsPlayer()) then return false end
	local ply = ent
	
	if (dmginfo:IsFallDamage() and ply:Alive()) then
		local _lookangle = ply:GetUp() - ply:GetAimVector()
		local _lookingdown = false
		if (_lookangle.z > 1.7) then _lookingdown = true end
		if (_lookingdown == true and ply:KeyDown(IN_ATTACK2)) then
			dmginfo:ScaleDamage(ROLLFACTOR)
			
			umsg.Start("startRoll", ply) 
			umsg.End()      
			
			ply:GetActiveWeapon().Weapon:SendWeaponAnim(ACT_VM_HOLSTER)
			ply:GetActiveWeapon().Weapon.Holstered = true;
			timer.Simple(ply:GetActiveWeapon().Weapon.SafetyTime, function(ply)
				ply:DrawViewModel(false)
			end, ply)
			timer.Simple(0.6, function(ply)
				if (ply:Alive()) then --he very well could have died from falling damage
					ply:GetActiveWeapon().Weapon:SendWeaponAnim(ACT_VM_DRAW)
					ply:DrawViewModel(true)
					ply:GetActiveWeapon().Weapon.Holstered = false
					ply:GetActiveWeapon().Weapon.Lowered = false
					ply:GetActiveWeapon():ResetLower()
				end
			end, ply)
			ply.RollSpeed = true
		else
			dmginfo:ScaleDamage(FALLFACTOR)
			local recoil = dmginfo:GetDamage()
			local _dir = math.Rand(-1,1)
			ply:ViewPunch(Angle(recoil, _dir * recoil * 0.8, _dir * recoil * 0.9))
		end
	end
end
hook.Add( "EntityTakeDamage", "ReduceFallDamage", ReduceFallDamage )

local function PlayerPainSounds( ent, inflictor, attacker, amount, dmginfo)
	if (ent:IsPlayer()) then
		local num = math.ceil(dmginfo:GetDamage()/10)
		num = num + math.random(-1, 1)
		if (num > 10) then num = 10 end
		if (num < 1) then num = 1 end
		ent:EmitSound("/vo/npc/male01/pain0" .. num .. ".wav", 50 + (dmginfo:GetDamage() / 2), 100)
	end
end
--hook.Add("EntityTakeDamage", "PlayerPainSounds", PlayerPainSounds)

local function SlowPlayerAnimation(ply, anim)
	ply:SetPlaybackRate(1.55)
end
hook.Add("SetPlayerAnimation", "SlowPlayerAnimation", SlowPlayerAnimation)

function GM:PlayerCanPickupWeapon(ply, wep)
	if not ply.OverridePickup then
		if (!ply:KeyDown(IN_USE)) then return false end
		
		if string.find( wep:GetClass(), "_gpk_" ) then
			--PickupViewPunch(ply)
			timer.Simple(0.05, function(ply)
				ply:SelectWeapon( wep:GetClass() )
			end, ply)
			return true
		elseif (wep:GetClass() == "weapon_pistol") then
			if (ply:HasWeapon("weapon_gpk_pistol")) then
				ply:GiveAmmo(18, "pistol")
				wep.Entity:Remove()
				--PickupViewPunch(ply)
			else
				local _override = ply.OverridePickup
				ply.OverridePickup = true
				ply:Give("weapon_gpk_pistol");
				ply:SelectWeapon("weapon_gpk_pistol")
				ply.OverridePickup = _override
				wep.Entity:Remove()
				--PickupViewPunch(ply)
			end
		elseif (wep:GetClass() == "weapon_smg1") then
			if (ply:HasWeapon("weapon_gpk_smg")) then
				ply:GiveAmmo(45, "smg1")
				wep.Entity:Remove()
				--PickupViewPunch(ply)
			else
				local _override = ply.OverridePickup
				ply.OverridePickup = true
				ply:Give("weapon_gpk_smg");
				ply:SelectWeapon("weapon_gpk_smg")
				ply.OverridePickup = _override
				wep.Entity:Remove();
				--PickupViewPunch(ply)
			end
		elseif (wep:GetClass() == "weapon_shotgun") then
			if (ply:HasWeapon("weapon_gpk_shotgun")) then
				ply:GiveAmmo(6, "buckshot")
				wep.Entity:Remove()
				--PickupViewPunch(ply)
			else
				local _override = ply.OverridePickup
				ply.OverridePickup = true
				ply:Give("weapon_gpk_shotgun");
				ply:SelectWeapon("weapon_gpk_shotgun")
				ply.OverridePickup = _override
				wep.Entity:Remove()
				--PickupViewPunch(ply)
			end
		elseif (wep:GetClass() == "weapon_crowbar") then
			if (ply:HasWeapon("weapon_gpk_crowbar")) then
				return false
			else
				local _override = ply.OverridePickup
				ply.OverridePickup = true
				ply:Give("weapon_gpk_crowbar");
				ply:SelectWeapon("weapon_gpk_crowbar")
				ply.OverridePickup = _override
				wep.Entity:Remove();
				--PickupViewPunch(ply)
			end
		elseif (wep:GetClass() == "weapon_stunstick") then
			if (ply:HasWeapon("weapon_gpk_stunstick")) then
				return false
			else
				local _override = ply.OverridePickup
				ply.OverridePickup = true
				ply:Give("weapon_gpk_stunstick");
				ply:SelectWeapon("weapon_gpk_stunstick")
				ply.OverridePickup = _override
				wep.Entity:Remove();
				--PickupViewPunch(ply)
			end
		end
		PickupViewPunch(ply)
	end
	return ply.OverridePickup
end

function PickupViewPunch(ply)
	ply:ViewPunch(Angle(10, -10, 10))
end

function PlayerMeta:GrabLedge()
	local trace = {}
	trace.start = self:GetShootPos() + Vector( 0, 0, 10 )
	trace.endpos = trace.start + (self:GetAimVector():Angle():Forward( ) * 30)
	trace.filter = self

	local trHi = util.TraceLine(trace)
	
	local trace = {}
	trace.start = self:GetShootPos()
	trace.endpos = trace.start + (self:GetAimVector():Angle():Forward( ) * 30)
	trace.filter = self

	local trLo = util.TraceLine(trace)
	
	if trLo and trHi and trLo.HitWorld and !trHi.Hit then
		return true
	else 
		return false
	end
	
	return false
end

function PlayerMeta:NearWall()
	local trace = {}
	trace.start = self:GetPos() + Vector( 0, 0, 50 )
	trace.endpos = trace.start + (self:GetAimVector() * 50)
	trace.filter = self

	local trFw = util.TraceLine(trace)
	
	local trace = {}
	trace.start = self:GetPos() + Vector( 0, 0, 50 )
	trace.endpos = trace.start + (self:GetAimVector():Angle():Right( ) * 50)
	trace.filter = self

	local trRi = util.TraceLine(trace)
	
	local trace = {}
	trace.start = self:GetPos() + Vector( 0, 0, 50 )
	trace.endpos = trace.start - (self:GetAimVector():Angle():Right( ) * 50)
	trace.filter = self

	local trLe = util.TraceLine(trace)
	
	if trFw and trRi and trLe and (trFw.HitWorld or trRi.HitWorld or trLe.HitWorld) then
		return true, trFw.HitWorld, trRi.HitWorld, trLe.HitWorld
	else 
		return false
	end
	
	return false
end

function SpeedDecay( )
	for _,pl in pairs( player.GetAll() ) do
		if not pl.WRunning or not pl:NearWall() then
			pl.AimVector = pl:GetAimVector()
		end
		if not pl.WRunning then
			pl.WRunStart = CurTime()
			pl.WTime = 0
			pl.AimVector = pl:GetAimVector()
			pl.Velocity = pl:GetVelocity()
		else
			pl.WTime = CurTime() - pl.WRunStart + 1
		end
	end
end
hook.Add( "Think", "SpeedDecay", SpeedDecay )

function PlayerMeta:GetSpeed( )
	if (self:KeyDown(IN_FORWARD) and (self:KeyDown(IN_MOVELEFT) or self:KeyDown(IN_MOVERIGHT))) then
		self.CurMaxSpeed = self.MaxSpeed * 0.90
	elseif (!self:KeyDown(IN_FORWARD) and !self:Crouching() and (self:KeyDown(IN_MOVELEFT) or self:KeyDown(IN_MOVERIGHT))) then
		self.CurMaxSpeed = self.MaxSpeed * 0.25
	else
		self.CurMaxSpeed = self.MaxSpeed
	end
	if (self:KeyDown(IN_BACK)) then
		self.CurMaxSpeed = self.MaxSpeed * 0.5
	end
	if (self:KeyDown(IN_FORWARD) or self:KeyDown(IN_MOVELEFT) or self:KeyDown(IN_MOVERIGHT) or self:KeyDown(IN_BACK)) then
		if (self.Speed < self.CurMaxSpeed * 0.25) then
			self.Speed = self.Speed + self.Acceleration * 4
		else
			self.Speed = self.Speed + self.Acceleration
		end
	end
	if (self:KeyDown(IN_DUCK)) then
		self.CurMaxSpeed = self.CrawlSpeed
	end
	if (!self:KeyDown(IN_FORWARD) and !self:KeyDown(IN_MOVELEFT) and !self:KeyDown(IN_MOVERIGHT) and !self:KeyDown(IN_BACK)) then
		self.Speed = self.Speed / 1.05
	end
	if (self:KeyDown(IN_SPEED)) then
		self.CurMaxSpeed = WALKSPEED
	end
	
	if self.Speed > self.CurMaxSpeed then self.Speed = self.Speed + (self.CurMaxSpeed - self.Speed * 0.99999999999999999999999) end
	if self.Speed < self.MinSpeed then self.Speed = self.MinSpeed end
	return self.Speed
end
 
function GM:SetupMove(ply, move)
		ply:SetCollisionGroup( COLLISION_GROUP_WEAPON )
        if (ply:OnGround()) then
			local speed = ply:GetSpeed()
            GAMEMODE:SetPlayerSpeed(ply, speed, speed)
			ply.WalljumpCombo = 0
		end
		
		if !ply:OnGround() and ply:KeyDown(IN_ATTACK2) and ply:NearWall() then
			ply.WRunning = true
			move:SetVelocity( Vector( ply:GetAimVector().x, ply:GetAimVector().y, ply:GetAimVector().z/2 ) * ply.Speed / ( ply.WTime/2) - Vector( 0, 0, 50*ply.WTime ) )
		elseif ply:OnGround() then
			ply.WRunning = false
		end
		if not ply.Hanging and ply:KeyDown(IN_ATTACK2) and ply:GrabLedge() then
			ply:SetMoveType(MOVETYPE_NONE)
			ply.Hanging = true
		end

	--[[if not ply.Hanging and ply:GetMoveType() == MOVETYPE_NONE then
		timer.Simple( 0.5, function() ply.Hanging = true end )
	end]]

	if ply.Hanging then
		if ply:KeyDown(IN_JUMP) then
			ply:SetMoveType(MOVETYPE_WALK)
			move:SetVelocity( Vector( 0, 0, 250 ) )
			timer.Simple( 0.5, function() ply.Hanging = false end )
		end
	end
	
	if ply.RollSpeed then
		--move:SetVelocity( Vector( ply.Velocity.x, ply.Velocity.y, 0 ) )
		ply.RollSpeed = false
	end
end

function GM:FinishMove(ply, move)
	
end

function util.QuickTrace( origin, dir, filter )
	local trace = {}

	trace.start = origin
	trace.endpos = origin + dir
	trace.filter = filter

	return util.TraceLine( trace )
end

function GPK_ChangeModel( ply, cmd, args )
	if !args or type(args[1]) != "string" then return end
	local mdl = args[1]
	ply:SetModel( mdl )
	ply:SaveData( mdl )
	ply:PrintMessage( 3, "Model changed to " .. mdl )
end
concommand.Add( "gpk_setmodel", GPK_ChangeModel )
